/*****************************************************************************************/
/* ECSE 426 - Microprocessor - Fall 2009
/* Lab Experiment 3 - Logic of the program
/* MAIN.C
/* @author: Danny Wu - 260238209 - B.Comp.Eng
/* @author: Han-Sheng Chin - 260209715 - B.Elec.Eng
/* @version: 09.10.23.1508 
/****************************************************************************************/

#include "msp430x14x.h"
#include "main.h"
#include "lcd.h"
#include "game.h"
#include "packet.h"

//register value
char *cc2500name[14] = {"PARTNUM", "VERSION", "FREQEST", "LQI",
"RSSI", "MARCSTATE", "WORTIME1", "WORTIME0", "PKSTATUS", "VCO_VC_DAC",
"TXBYTES", "RXBYTES", "RCCTRL1_STATUS", "RCCTRL0_STATUS"};
char *cc2500configReg[0x2F] = {"IOCFG2","IOCFG1","IOCFG0","FIFOTHR","SYNC1","SYNC0","PKTLEN","PKTCTRL1","PKTCTRL0","ADDR","CHANNR","FSCTRL1","FSCTRL0","FREQ2","FREQ1","FREQ0",
"MDMCFG4","MDMCFG3","MDMCFG2","MDMCFG1","MDMCFG0","DEVIATN","MCSM2","MCSM1","MCSM0","FOCCFG","BSCFG","AGCTRL2","AGCTRL1","AGCTRL0","WOREVT1","WOREVT0",
"WORCTRL","FREND1","FREND0","FSCAL3","FSCAL2","FSCAL1","FSCAL0","RCCTRL1","RCCTRL0","FSTEST","PTEST","AGCTEST","TEST2","TEST1","TEST0"};


int state;    // Global variable for state of the finite state machine.
int func;     // Global variable for determining which option to use in input interrupt.
int exit;     // Global variable for determining whether to exit program or not.
char input;    // Global variable to store the input values from the keyboard.
int waitInput;  // Global variable to determine if the FSM is waiting for input.
int regAdd;     // Global variable for the register address to be modified.
int regVal;     // Global variable for the new register value.
char msg[64];     // message to be transmitted
int msgCtr;     //counter for msg length

PACKET lastReceived;
char gameSecretNum[4];
int guessCount;

char name[24];

//TI variables
char txBuffer[64];
char rxBuffer[64];

//FSM variables
int inputCount = 0;
char inputOne, inputTwo;

/**
 * Main function
 * Used to run the logic of our program
 * *Initialize configuration of the clock
 * *Enable interrupts
 */
void main(void){  
  char x;
  int i=0;

  //initialize configuration of the clock
  WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
  BCSCTL1 &= ~XT2OFF;                   // XT2OFF
  BCSCTL2 |= SELS;                      // MCLK = SMCLK = XT2 (safe)
  _EINT();                              // Enable interrupts
  
  //start configuration
  initRsUART();
  TI_CC_SPISetup(); //calling TI code or initSpiUART(); TI_CC_SPISetup()
  ccResetChip();  
  clearScreen(); 
  ccConfigBeacon();
   
  //store and reload value from flash
  clearAllFlash();
  saveToFlash();
  loadFromFlash();
  
  //lcd initialization
  initLCD();

  //start FSM
  startFSM();

  //leave program
  println("Goodbye!");
  while(TRUE);

}//end main

void startFSM(void){
  //start the FSM of the program
  while(exit != 1){
  
    switch(state){

      case 0:     // Ready mode. Print menu and wait for user input.
        printMenu();
        func = 0;
        state = 8;  // Wait
        break;

      case 1:     // Dump registers mode. Print the data of all the registers.
        dumpConfigReg();
        println(""); 
        dumpStatusReg();
        println("Press ENTER for menu or ESC to exit program.");
        func = 1;
        state = 8;  // Wait
        break;

      case 2:     // Modify register mode. Print the data of the old value and wait for user input on new value.
        modReg();
        println("Press ENTER for menu or ESC to exit program.");
        func = 1;
        state = 8;  // Wait
        break;

      case 3:     // Sending and receiving data mode. Input destination and string.
        sendReceive();
        println("Press ENTER for menu or ESC to exit program.");
        func = 1;
        state = 8;  // Wait
        break;

      case 4:     // Receiving only mode.
        receiveOnly();
        println("Press ENTER for menu or ESC to exit program.");
        func = 1;
        state = 8;  // Wait
        break;

      case 5:
        println("Game mode!");
        startGame();
        break;      
      
      case 6:     // Exit program.
        exit = 1;
        break;

      case 8:     // Wait for input
        break;
    }//end switch  
  }// end of while loop
}//end startFSM


//logic of the final state machine
void logicFSM (char val){
  switch (func) {
      case 0: // main menu
        switch(val) {
          case 0x31: // key '1': dump all registers
            putChar('\b');
            putChar(val);
            input = 1;
            break;
          case 0x32: // key '2': modify a register
            putChar('\b');
            putChar(val);
            input = 2;
            break;
          case 0x33: // key '3': send and receive
            putChar('\b');
            putChar(val);
            input = 3;
            break;
          case 0x34: // key '4': receive only
            putChar('\b');
            putChar(val);
            input = 4;
            break;
          case 0x35: // key '5': game mode
            putChar('\b');
            putChar(val);
            input = 5;
            break;
          case 0x1b: // escape key exits program
            exit = 1;
            break;
          case 0x0d: // enter key
            state = input;
            input = 0;
            break;
          case 0x08: //backspace
            putChar('\b');
            putChar(0x20);
            //putChar('\b');       
            break;
          default:
  //          println(" In*valid input! ");
  //          putChar(val);
  //          println("Select an option:  ");
            break;
        } // end nested switch of case func=0
        break;
      case 1:                                                  // Option to print menu or exit at the end of each function.
        switch(val) {
          case 0x0d: // enter key
            state = 0;
            break;
          case 0x1b: // escape key
            exit = 1;
            break;
          default:
            break;
        } // end nested switch of case func=1
        break;
      case 2:                                                // Modify register mode - input register address
        switch(val) {
          case 0x1b: // excape key
            println("Operation aborted!");
            state = 0;
            func = 0;
            waitInput = 0;
            break;
          case 0x0d: // enter key
            if (inputCount == 2)
            {
  
              regAdd = combineInput(inputOne, inputTwo);        // Combine the two inputs into one. Function not written yet.
              println("Register address is: ");
              printHex(regAdd); //debug
  
              inputCount = 0;
              waitInput = 0;
            }
            else
            {
              println("Invalid input! Press escape to return to menu!");
            }
            break;
          default:
            // Store the value of the register address.
            if (inputCount == 0)
            {
              inputOne = val;
              putChar(inputOne);
              inputCount++;
            }
            else if (inputCount == 1)
            {
              inputTwo = val;
              putChar(inputTwo);
              inputCount++;
            }
            break;
        } // end nested switch of case func=2
        break;
      case 3:                                                // Modify register mode - input register value
        switch(val) {
          case 0x1b: // excape key
            println("Operation aborted!");
            state = 0;
            func = 0;
            waitInput = 0;
            break;
          case 0x0d: // enter key
            if (inputCount == 2)
            {
  
              regVal = combineInput(inputOne, inputTwo);        // Combine the two inputs into one. Function not written yet.
              println("New register value is ");
  
              printHex(regVal); //debug
              inputCount = 0;
              waitInput = 0;
              spiWriteReg(regAdd, regVal);
              println("Register changed!");
            }
            else
            {
              println("Invalid input! Press escape to return to menu!");
            }
            break;
          default:
            // Store the new value of the register.
            if (inputCount == 0)
            {
              inputOne = val;
              putChar(inputOne);
              inputCount++;
            }
            else if (inputCount == 1)
            {
              inputTwo = val;
              putChar(inputTwo);
              inputCount++;
            }
            break;
        } // end nested switch of case func=3
        break;
  
        case 5:
          switch(val) {
            case 0x08: //backspace
              putChar('\b');
              putChar(0x20);
              putChar('\b');  
              msgCtr--;
              msg[msgCtr] = '\0';           
              break;
            case 0x0d: // enter key
              waitInput = 0;
              break;
            case 0x1b: // escape key
              println("Operation aborted!");
              state = 0;
              func = 0;
              waitInput = 0;
              break;
            default:
              msg[msgCtr] = val;
              putChar(msg[msgCtr]);
              msgCtr++;
              break;
          } // end nested switch of case func=5
          break;
    } // end switch
}//end logicFSM


/**
 * This function is only used to print the menu interface.
 *
 */
void printMenu(void) {
  clearScreen();
  println("*******************************************************************");
  println("Welcome to Danny & Han's CC2500 Wireless Transceiver Interface");
  println("*******************************************************************");
  println("1. Dump all registers.");
  println("2. Modify content of a register.");
  println("3. Send and receive data packets.");
  println("4. Receive data packets only.");
  println("5. Game mode.");
  println("Select an option:  ");
} //end printMenu

/**
 *  This function dumps all the configuration registers
 */
void dumpConfigReg(void) {
  char i;
  int ctr = 0;
  char *configReg[0x2F] = {"IOCFG2","IOCFG1","IOCFG0","FIFOTHR","SYNC1","SYNC0","PKTLEN","PKTCTRL1","PKTCTRL0","ADDR","CHANNR","FSCTRL1","FSCTRL0","FREQ2","FREQ1","FREQ0",
                   "MDMCFG4","MDMCFG3","MDMCFG2","MDMCFG1","MDMCFG0","DEVIATN","MCSM2","MCSM1","MCSM0","FOCCFG","BSCFG","AGCTRL2","AGCTRL1","AGCTRL0","WOREVT1","WOREVT0",
                   "WORCTRL","FREND1","FREND0","FSCAL3","FSCAL2","FSCAL1","FSCAL0","RCCTRL1","RCCTRL0","FSTEST","PTEST","AGCTEST","TEST2","TEST1","TEST0"};
  println("*****************************************");
  println("Start dumping configuration registers");
  println("*****************************************");
  println("\nADDRESS\t\tREG NAME\t\tVALUE\n");
  for(i=0x00; i < 0x2F;i++){ 
    println("");
    printHex(i);
    print("\t\t");
    print(configReg[ctr++]);
    print("    \t\t");
    printHex(spiReadReg(i));
  }//end for
  println("*****************************************");
  println("End dumping configuration registers");
  println("*****************************************");
}//end dumpConfigReg

/**
 *  This function dumps all the status registers
 */
void dumpStatusReg(void) {
  char i;
  int ctr = 0;
  char *regName[14] = {"PARTNUM  ", "VERSION  ", "FREQEST  ", "LQI     ",
                      "RSSI    ", "MARCSTATE", "WORTIME1", "WORTIME0", "PKSTATUS", "VCO_VC_DAC",
                      "TXBYTES ", "RXBYTES  ", "RCCTRL1_STATUS", "RCCTRL0_STATUS"};
  println("*****************************************");
  println("Start dumping status registers");
  println("*****************************************");
  println("\nADDRESS\t\tREG NAME\t\tVALUE\n");
  for(i=0x30; i < 0x3E;i++){ 
    println("");
    printHex(i);
    print("\t\t");
    print(regName[ctr++]);
    print("\t\t");
    printHex(spiReadReg(i));
  }//end for
  println("*****************************************");
  println("End dumping status registers");
  println("*****************************************");
}//end dumpConfigReg


void modReg(void) {
  char x;
  println("************************************************");
  println("2. Modify content of a register");
  println("************************************************");
  println("Choose desired register to be modified: 0x");
  func = 2;
  waitInput = 1;
  while (waitInput);                // Wait for input
  if (func == 2)
  {
    x = spiReadReg(regAdd);
//    if(x < 0x2F){
      println("Register name is ");   // Still have to figure out how to print register name.
      print(cc2500configReg[regAdd]);
      println(" Old value = ");                    // Still have to figure out how to print old value.
      printHex(x);
      println(" New value = 0x");
      func = 3;
      waitInput = 1;
      while (waitInput);                // Wait for input
//    }else{
//      println("Configuration address is out of bound!\n");
//    }//end if 
  } // end if
} //end modReg

/**
 * This function is used to send and receive
 *
 *
 */
void sendReceive(void) {        // Function to send and receive message.
  char tmp;

  msgCtr = 0;
  println("************************************************");
  println("3. Send and receive data packets");
  println("************************************************");
  println("---Press [ENTER] to send---"); 
  println("Enter the message to send: ");
  func = 5;
  waitInput = 1;
  while(waitInput);
  //send message
  if(func == 5){
    println("before the TRaNSFER~~~");
    ccTX(msg);
   
    //wait until its idle
    while(!((tmp = TI_CC_SPIReadStatus(MARCSTATE)) == 0x01)) {
      printHex(tmp);
      printHex(TI_CC_SPIReadStatus(TXBYTES));
    }
//    //receive mode
//    ccCommandStrobe(SFRX);
//    ccCommandStrobe(SRX);
  }//end if
} //end sendReceive

void receiveOnly(void) {
  println("************************************************");
  println("4. Receive data packets only");
  println("************************************************");

  //receive mode
  ccCommandStrobe(SRX);
  //ccRX();  // Code to receive data only.
} //end receiveOnly
